package cn.xeblog.server.action.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.comparator.VersionComparator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.xeblog.commons.constants.IpConstants;
import cn.xeblog.commons.entity.*;
import cn.xeblog.commons.enums.Action;
import cn.xeblog.commons.enums.MessageType;
import cn.xeblog.commons.enums.Permissions;
import cn.xeblog.server.action.ChannelAction;
import cn.xeblog.server.annotation.DoAction;
import cn.xeblog.server.builder.ResponseBuilder;
import cn.xeblog.server.cache.UserCache;
import cn.xeblog.server.config.GlobalConfig;
import cn.xeblog.server.config.ServerConfig;
import cn.xeblog.server.constant.CommonConstants;
import cn.xeblog.server.factory.ObjectFactory;
import cn.xeblog.server.service.AbstractResponseHistoryService;
import cn.xeblog.server.util.IpUtil;
import cn.xeblog.server.util.SensitiveWordUtils;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @author anlingyi
 * @date 2020/8/14
 */
@Slf4j
@DoAction(Action.LOGIN)
public class LoginActionHandler implements ActionHandler<LoginDTO> {

  /**
   * 最后的消息数量，即最近的n条消息
   */
  private static final int LAST_MESSAGE_NUM = 15;

  @Override
  public void handle(ChannelHandlerContext ctx, LoginDTO body) {

    String currentPluginVersion = CommonConstants.PLUGIN_VERSION;

    String userPluginVersion = body.getPluginVersion();

    // 这里是对用户版本和服务端版本补全，让两端版本长度一致
    if (StrUtil.isNotBlank(userPluginVersion)) {
      int len = currentPluginVersion.length();
      int len2 = userPluginVersion.length();
      int k = len - len2;
      String padding = "";
      for (int i = Math.abs(k); i > 0; i--) {
        padding += "0";
      }
      if (k > 0) {
        userPluginVersion += padding;
      } else if (k < 0) {
        currentPluginVersion += padding;
      }
    }

    // 比较版本，这里会用"."对用户版本和服务端版本进行切割,用于比较两端版本是否一致
    int versionState = VersionComparator.INSTANCE.compare(currentPluginVersion, userPluginVersion);
    // 客户端版本与服务端是否一致
    if (versionState > 0) {
      ctx.writeAndFlush(ResponseBuilder.system("温馨提醒~ 请尽快更新插件版本至v" + CommonConstants.PLUGIN_VERSION + "！"));
      ctx.close();
      return;
    }
    // 判断服务端版本是否有问题
    if (versionState < 0) {
      ctx.writeAndFlush(ResponseBuilder.system("当前服务端版本过低！你的版本：v" + body.getPluginVersion()
          + "，服务端版本：v" + CommonConstants.PLUGIN_VERSION));
      ctx.close();
      return;
    }

    // 判断是否重连
    boolean isReconnect = body.isReconnected();
    // 去除字符串中的空格\\s*,回车\n,换行符\r,制表符\t
    String username = body.getUsername().replaceAll("\\s*|\t|\r|\n", "");

    // 判断用户名是否重复
    if (UserCache.existUsername(username)) {
      ctx.writeAndFlush(ResponseBuilder.system("[" + username + "]昵称重复！"));
      ctx.close();
      return;
    }

        // 判断是否有敏感词
        if (SensitiveWordUtils.hasSensitiveWord(username)) {
            ctx.writeAndFlush(ResponseBuilder.system("昵称含有违规字符，请修改后重试！"));
            ctx.close();
            return;
        }

        if (StrUtil.isBlank(body.getUuid())) {
            ctx.writeAndFlush(ResponseBuilder.system("未获取到UUID，请尝试重新登录！"));
            ctx.close();
            return;
        }

        // 拼装用户信息
        String id = ChannelAction.getId(ctx);
        final String ip = IpUtil.getIpByCtx(ctx);
        final IpRegion ipRegion = IpUtil.getRegionByIp(ip);
        String configToken = ServerConfig.getConfig().getToken();
        boolean isAdmin = StrUtil.isNotBlank(configToken) && StrUtil.equals(configToken, body.getToken());
        User user = new User(id, username, body.getStatus(), ip, ipRegion, ctx.channel());
        user.setUuid(body.getUuid());
        user.setRole(isAdmin ? User.Role.ADMIN : User.Role.USER);
        user.setPermit(GlobalConfig.USER_PERMIT_CACHE.getOrDefault(body.getUuid(), Permissions.ALL.getValue()));
        UserCache.add(id, user);

        // 对在线用户发送消息.即登录成功发送系统公告
        ChannelAction.add(ctx.channel());
        ChannelAction.sendOnlineUsers(user);
        // 设置用户为在线
        ChannelAction.sendUserState(user, UserStateMsgDTO.State.ONLINE);
        // 发送重连成功消息
        if (isReconnect) {
            user.send(ResponseBuilder.system("重新连接服务器成功！"));
        }
        // 发送系统消息
        user.send(ResponseBuilder.system("修身洁行，言必由绳墨。"));

        // 最近的30条消息
        List<Response> historyMsgList = ObjectFactory.getObject(AbstractResponseHistoryService.class).getHistory(30);
        // 系统消息
        final String loginMsg = StrUtil.format("[{}·{}]进入了鱼塘！",
                MapUtil.getStr(IpConstants.SHORT_PROVINCE, ipRegion.getProvince(), ipRegion.getCountry()), user.getUsername());
        ChannelAction.send(ResponseBuilder.system(loginMsg));

        // 历史消息，最近的30条
        if (CollectionUtil.isNotEmpty(historyMsgList)) {
            user.send(ResponseBuilder.build(null, new HistoryMsgDTO(historyMsgList), MessageType.HISTORY_MSG));
        }
    }

}
